package com.rainbow.gray.plugin.framework.starter.service.aop;

import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.rainbow.gray.framework.constant.GrayConstant;
import com.rainbow.gray.framework.utils.StrategyUtil;
import com.rainbow.gray.plugin.framework.starter.service.constant.ServiceStrategyConstant;
import com.rainbow.gray.plugin.framework.starter.service.context.ServiceStrategyContextHolder;

/**
 * <p>Title: Nepxion Discovery</p>
 * <p>Description: Nepxion Discovery</p>
 * <p>Copyright: Copyright (c) 2017-2050</p>
 * <p>Company: Nepxion</p>
 * @author Haojun Ren
 * @version 1.0
 */

import feign.RequestInterceptor;
import feign.RequestTemplate;

public class FeignStrategyInterceptor extends AbstractStrategyInterceptor implements RequestInterceptor {
    @Autowired
    protected ServiceStrategyContextHolder serviceStrategyContextHolder;

    // Feign上核心策略Header是否传递。当全局订阅启动时，可以关闭核心策略Header传递，这样可以节省传递数据的大小，一定程度上可以提升性能。核心策略Header，包含如下
    // 1. n-d-version
    // 2. n-d-region
    // 3. n-d-address
    // 4. n-d-version-weight
    // 5. n-d-region-weight
    // 6. n-d-id-blacklist
    // 7. n-d-address-blacklist
    // 8. n-d-env (不属于灰度蓝绿范畴的Header，只要外部传入就会全程传递)
    @Value("${" + ServiceStrategyConstant.SPRING_APPLICATION_STRATEGY_FEIGN_CORE_HEADER_TRANSMISSION_ENABLED + ":true}")
    protected Boolean feignCoreHeaderTransmissionEnabled;

    public FeignStrategyInterceptor(String contextRequestHeaders, String businessRequestHeaders) {
        super(contextRequestHeaders, businessRequestHeaders);
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        interceptInputHeader();

        applyInnerHeader(requestTemplate);
        applyOuterHeader(requestTemplate);

        interceptOutputHeader(requestTemplate);
    }

    private void applyInnerHeader(RequestTemplate requestTemplate) {
        requestTemplate.header(GrayConstant.N_D_SERVICE_GROUP, pluginAdapter.getGroup());
        requestTemplate.header(GrayConstant.N_D_SERVICE_TYPE, pluginAdapter.getServiceType());
        requestTemplate.header(GrayConstant.N_D_SERVICE_ID, pluginAdapter.getServiceId());
        requestTemplate.header(GrayConstant.N_D_SERVICE_ADDRESS, pluginAdapter.getHost() + ":" + pluginAdapter.getPort());
        requestTemplate.header(GrayConstant.N_D_SERVICE_VERSION, pluginAdapter.getVersion());
        requestTemplate.header(GrayConstant.N_D_SERVICE_REGION, pluginAdapter.getRegion());
        requestTemplate.header(GrayConstant.N_D_SERVICE_ENVIRONMENT, pluginAdapter.getEnvironment());
        requestTemplate.header(GrayConstant.N_D_SERVICE_ZONE, pluginAdapter.getZone());
    }

    private void applyOuterHeader(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes();
        if (attributes == null) {
            return;
        }

        HttpServletRequest previousRequest = attributes.getRequest();
        Enumeration<String> headerNames = previousRequest.getHeaderNames();
        if (headerNames == null) {
            return;
        }

        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = previousRequest.getHeader(headerName);
            boolean isHeaderContains = isHeaderContainsExcludeInner(headerName.toLowerCase());
            if (isHeaderContains) {
                if (feignCoreHeaderTransmissionEnabled) {
                    requestTemplate.header(headerName, headerValue);
                } else {
                    boolean isCoreHeaderContains = StrategyUtil.isCoreHeaderContains(headerName);
                    if (!isCoreHeaderContains) {
                        requestTemplate.header(headerName, headerValue);
                    }
                }
            }
        }
    }

    private void interceptOutputHeader(RequestTemplate requestTemplate) {
        if (!interceptDebugEnabled) {
            return;
        }

        System.out.println("------- " + getInterceptorName() + " Intercept Output Header Information ------");
        Map<String, Collection<String>> headers = requestTemplate.headers();
        for (Map.Entry<String, Collection<String>> entry : headers.entrySet()) {
            String headerName = entry.getKey();
            boolean isHeaderContains = isHeaderContains(headerName.toLowerCase());
            if (isHeaderContains) {
                Collection<String> headerValue = entry.getValue();

                System.out.println(headerName + "=" + headerValue);
            }
        }
        System.out.println("--------------------------------------------------");
    }

    @Override
    protected String getInterceptorName() {
        return "Feign";
    }
}